package cn.tedu.javacv159.util;

import cn.tedu.common.ex.ResultCodeEnum;
import cn.tedu.common.ex.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.MatVector;
import org.bytedeco.opencv.opencv_core.Rect;
import org.bytedeco.opencv.opencv_stitching.Stitcher;
import org.bytedeco.opencv.opencv_videoio.VideoCapture;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
import static org.bytedeco.opencv.global.opencv_videoio.CAP_PROP_FPS;


@Slf4j
public class ImageStitchingUtils {

    public static Mat concatenateTwoImages(Mat mat1, Mat mat2) {
        // 创建Stitcher对象，默认创建的是全景图模式
        Stitcher stitcher = Stitcher.create(Stitcher.PANORAMA);

        // 准备要拼接的图像
        Mat panorama = new Mat();
        MatVector vector = new MatVector();
        // 将List<Mat>转换为Mat[]
        vector.put(mat1, mat2);

        // 尝试拼接图像
        int stitch = stitcher.stitch(vector, panorama);

        switch (stitch) {
            case Stitcher.OK:
                if (panorama.clone().cols() > mat1.cols() * 2) {
                    throw new ServiceException(ResultCodeEnum.PARAMETER_ERROR, ErrorConstant.UNKNOWN_ERROR);
                }
                imwrite("C:\\Users\\white\\Desktop\\img\\img" + UUID.randomUUID() + ".jpg", panorama);
                return panorama;
            case Stitcher.ERR_CAMERA_PARAMS_ADJUST_FAIL:
                throw new ServiceException(ResultCodeEnum.PARAMETER_ERROR, ErrorConstant.ERR_CAMERA_PARAMS_ADJUST_FAIL);
            case Stitcher.ERR_NEED_MORE_IMGS:
                throw new ServiceException(ResultCodeEnum.PARAMETER_ERROR, ErrorConstant.ERR_NEED_MORE_IMGS);
            case Stitcher.ERR_HOMOGRAPHY_EST_FAIL:
                throw new ServiceException(ResultCodeEnum.PARAMETER_ERROR, ErrorConstant.ERR_HOMOGRAPHY_EST_FAIL);
            default:
                throw new ServiceException(ResultCodeEnum.PARAMETER_ERROR, ErrorConstant.UNKNOWN_ERROR);
        }
    }

    public static File transform(MultipartFile file) throws IOException {
        Path tempFilePath = Files.createTempFile("uploaded_video", file.getOriginalFilename());
        Files.copy(file.getInputStream(), tempFilePath, StandardCopyOption.REPLACE_EXISTING);
        return tempFilePath.toFile();
    }

    public static List<Mat> videoToImages(File videoFile, Double intervalTime) {
        List<Mat> images = new ArrayList<>();
        System.out.println(videoFile.getAbsolutePath());
        VideoCapture capture = new VideoCapture(videoFile.getAbsolutePath());
        if (!capture.isOpened()) {
            throw new ServiceException(ResultCodeEnum.MEDIA_TYPE_NOT_SUPPORTED, "Error opening video file.");
        }

        double frameRate = capture.get(CAP_PROP_FPS); // 获取视频帧率
        double targetIntervalInSeconds = intervalTime; // 目标间隔时间（0.5秒）
        int framesToSkip = (int) Math.round(frameRate * targetIntervalInSeconds); // 计算要跳过的帧数

        Mat frame = new Mat();
        int frameNumber = 0;

        while (capture.read(frame)) {
            if (frame.empty()) {
                break; // No more frames
            }

            if ((frameNumber % framesToSkip) == 0) { // 每隔特定帧数截取
                images.add(frame.clone());
                imwrite("C:\\Users\\white\\Desktop\\pic\\snap_" + frameNumber + ".jpg", frame);
            }

            frameNumber++;
        }

        // Release resources
        capture.release();
        return images;
    }

    public static List<Mat> imageSplit(Mat originalImage) {
        List<Mat> smallImages = new ArrayList<>();

        // 获取原始图像的宽度和高度
        int originalWidth = originalImage.cols();
        int originalHeight = originalImage.rows();

        // 计算分割后的小图数量
        int numSmallImages = (int) Math.ceil((double) originalWidth / 1920);

        // 计算每个小图的目标宽度
        int targetSmallImageWidth = (int) Math.ceil((double) originalWidth / numSmallImages);

        // 分割图像
        for (int i = 0; i < numSmallImages; i++) {
            // 计算当前小图的起始和结束列索引
            int startX = i * targetSmallImageWidth;
            int endX = Math.min((i + 1) * targetSmallImageWidth, originalWidth);

            // 提取当前小图的区域
            Mat smallImage = new Mat(originalImage, new Rect(startX, 0, endX - startX, originalHeight));

            // 保存小图
            imwrite("C:\\Users\\white\\Desktop\\small\\small_" + UUID.randomUUID() + ".jpg", smallImage);
            smallImages.add(smallImage);
        }
        return smallImages;
    }

    private Mat toMat(Frame frame) {
        OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
        return converter.convert(frame);
    }

}
